﻿/****************************************************************
*   作者：Morain
*   创建时间：2018/2/22 18:50:12
*   描述说明：
*****************************************************************/
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Model
{
  /// <summary>
  /// 网络组件
  /// </summary>
  public abstract class NetworkComponent : Component
  {
    private AService service;
    public AppType AppType;
    public Dictionary<long, Session> sessions = new Dictionary<long, Session>();

    public IMessagePacker MessagePacker { get; set; }

    /// <summary>
    /// 转发器
    /// </summary>
    public IMessageDispatcher MessageDispatcher { get; set; }

    public void Awake(NetworkProtocol networkProtocol)
    {
      switch (networkProtocol)
      {
        case NetworkProtocol.TCP:
          this.service = new TService();
          break;
        case NetworkProtocol.KCP:
          break;
        default:
          break;
      }
    }

    public void Awake(NetworkProtocol networkProtocol, IPEndPoint iPEndPoint)
    {
      switch (networkProtocol)
      {
        case NetworkProtocol.TCP:
          this.service = new TService(iPEndPoint);
          break;
        case NetworkProtocol.KCP:
          break;
        default:
          break;
      }

      StartAccept();
    }

    private async void StartAccept()
    {
      while (true)
      {
        if (this.Id == 0)
        {
          return;
        }
        await this.Accept();
      }
    }

    public virtual async Task<Session> Accept()
    {
      AChannel channel = await this.service.AcceptChannel();

      Session session = ComponentFactory.CreateWithId<Session, NetworkComponent, AChannel>(IdGenerater.GeneraterId(), this, channel);
      session.Parent = this;
      channel.ErrorCallback += (c, e) =>
      {
        this.Remove(session.Id);
        //Log.Debug($"Client[{channel.RemoteAddress}] connection close!");
      };
      this.sessions.Add(session.Id, session);

      //Log.Debug($"Client[{channel.RemoteAddress}] connection open!");

      return session;
    }

    public virtual void Remove(long id)
    {
      Session session;
      if (!this.sessions.TryGetValue(id, out session))
        return;

      this.sessions.Remove(id);
      session.Dispose();
    }

    public Session Get(long id)
    {
      Session session;
      this.sessions.TryGetValue(id, out session);
      return session;
    }

    /// <summary>
    /// 用于连接一个服务端
    /// </summary>
    /// <param name="iPEndPoint"></param>
    /// <returns></returns>
    public virtual Session Create(IPEndPoint iPEndPoint)
    {
      try
      {
        AChannel channel = this.service.ConnectChannel(iPEndPoint);
        Session session = ComponentFactory.CreateWithId<Session, NetworkComponent, AChannel>(IdGenerater.GeneraterId(), this, channel);
        session.Parent = this;
        channel.ErrorCallback += (c, e) => { this.Remove(session.Id); };
        this.sessions.Add(session.Id, session);
        return session;
      }
      catch (Exception e)
      {
        Log.Error(e.ToString());
        return null;
      }
    }

    /// <summary>
    /// 留给KCP用的
    /// </summary>
    public void Update()
    {
      if (this.service == null)
      {
        return;
      }
      this.service.Update();
    }

    public override void Dispose()
    {
      if (this.Id == 0)
      {
        return;
      }

      base.Dispose();

      foreach (var session in this.sessions.Values)
      {
        session.Dispose();
      }
      this.service.Dispose();
    }
  }
}